"""
日志管理器模块
基于Python标准库logging和structlog实现线程安全的日志管理
"""

import logging
import logging.handlers
import os
import sys
import threading
from pathlib import Path
from typing import Optional, Dict, Any

import structlog
from structlog.stdlib import LoggerFactory

from .log_config import LogConfig


class ThreadSafeLoggerManager:
    """线程安全的日志管理器"""
    
    _instance = None
    _lock = threading.Lock()
    _initialized = False
    
    def __new__(cls):
        if cls._instance is None:
            with cls._lock:
                if cls._instance is None:
                    cls._instance = super().__new__(cls)
        return cls._instance
    
    def __init__(self):
        if not self._initialized:
            with self._lock:
                if not self._initialized:
                    self.config = LogConfig()
                    self._setup_logging()
                    self._initialized = True
    
    def reset(self):
        """重置日志管理器的状态并重新初始化"""
        with self._lock:
            self._initialized = False
            self.__init__()
    
    def _setup_logging(self):
        """设置日志系统"""
        # 配置structlog
        structlog.configure(
            processors=[
                structlog.stdlib.filter_by_level,
                structlog.stdlib.add_logger_name,
                structlog.stdlib.add_log_level,
                structlog.stdlib.PositionalArgumentsFormatter(),
                structlog.processors.TimeStamper(fmt="iso"),
                structlog.processors.StackInfoRenderer(),
                structlog.processors.format_exc_info,
                self._add_thread_info,
                self._add_caller_info,
                structlog.processors.UnicodeDecoder(),
                structlog.processors.JSONRenderer() if self.config.get_format_type() == 'json'
                else self._custom_formatter,
            ],
            context_class=dict,
            logger_factory=LoggerFactory(),
            wrapper_class=structlog.stdlib.BoundLogger,
            cache_logger_on_first_use=True,
        )
        
        # 配置标准库logging
        root_logger = logging.getLogger()
        root_logger.setLevel(self._get_logging_level())
        
        # 清除现有handlers
        for handler in root_logger.handlers[:]:
            root_logger.removeHandler(handler)
        
        # 添加控制台handler
        if self.config.is_console_enabled():
            console_handler = logging.StreamHandler(sys.stdout)
            console_handler.setLevel(self._get_logging_level())
            root_logger.addHandler(console_handler)
        
        # 添加文件handler
        if self.config.is_file_logging_enabled():
            self._setup_file_handler(root_logger)
    
    def _setup_file_handler(self, logger: logging.Logger):
        """设置文件日志handler"""
        log_file = self.config.get_file_path()
        
        # 确保日志目录存在
        log_dir = Path(log_file).parent
        log_dir.mkdir(parents=True, exist_ok=True)
        
        # 使用RotatingFileHandler实现日志轮转
        file_handler = logging.handlers.RotatingFileHandler(
            filename=log_file,
            maxBytes=self.config.get_file_max_size(),
            backupCount=self.config.get_file_backup_count(),
            encoding='utf-8'
        )
        file_handler.setLevel(self._get_logging_level())
        logger.addHandler(file_handler)
    
    def _get_logging_level(self) -> int:
        """获取logging模块的日志级别"""
        level_map = {
            'DEBUG': logging.DEBUG,
            'INFO': logging.INFO,
            'WARN': logging.WARNING,
            'ERROR': logging.ERROR
        }
        return level_map.get(self.config.get_log_level(), logging.INFO)
    
    @staticmethod
    def _add_thread_info(logger, method_name, event_dict):
        """添加线程信息到日志
        """
        current_thread = threading.current_thread()
        event_dict['thread_id'] = current_thread.ident
        event_dict['thread_name'] = current_thread.name
        return event_dict
    
    @staticmethod
    def _add_caller_info(logger, method_name, event_dict):
        """添加调用者信息到日志
        """
        import inspect
        
        # 获取调用栈，跳过structlog内部的调用
        frame = inspect.currentframe()
        try:
            # 向上查找，跳过日志库内部的调用
            for _ in range(10):  # 最多查找10层
                frame = frame.f_back
                if frame is None:
                    break
                
                filename = frame.f_code.co_filename
                # 跳过structlog和logging相关的文件
                if ('structlog' not in filename and
                    'logging' not in filename and
                    'logger_manager.py' not in filename):
                    event_dict['pathname'] = filename
                    event_dict['lineno'] = frame.f_lineno
                    break
        finally:
            del frame
        
        return event_dict
    
    @staticmethod
    def _custom_formatter(logger, method_name, event_dict):
        """自定义日志格式化器
        """
        timestamp = event_dict.pop('timestamp', '')
        level = event_dict.pop('level', '').upper()
        thread_id = event_dict.pop('thread_id', '')
        thread_name = event_dict.pop('thread_name', '')
        
        # 获取调用位置信息
        frame_info = ""
        if 'pathname' in event_dict and 'lineno' in event_dict:
            filename = os.path.basename(event_dict.pop('pathname', ''))
            lineno = event_dict.pop('lineno', '')
            frame_info = f"[{filename}:{lineno}]"
        
        # 构建消息
        event = event_dict.pop('event', '')
        
        # 添加额外的上下文信息
        extra_info = []
        for key, value in event_dict.items():
            if not key.startswith('_'):  # 忽略内部字段
                extra_info.append(f"{key}={value}")
        
        extra_str = f" ({', '.join(extra_info)})" if extra_info else ""
        
        # 格式化最终消息
        formatted_msg = f"[{timestamp}] [{level}] [Thread-{thread_id}:{thread_name}] {frame_info} {event}{extra_str}"
        
        return formatted_msg
    
    @staticmethod
    def get_logger(name: str) -> structlog.stdlib.BoundLogger:
        """获取logger实例"""
        return structlog.get_logger(name)


# 全局实例
_manager = None
_manager_lock = threading.Lock()


@staticmethod
def get_logger(name: str) -> structlog.stdlib.BoundLogger:
    """
    获取logger实例的便捷函数
    :param name: logger名称，通常使用 __name__
    :return: structlog logger实例
    """
    global _manager
    if _manager is None:
        with _manager_lock:
            if _manager is None:
                _manager = ThreadSafeLoggerManager()
    
    return _manager.get_logger(name)


@staticmethod
def reload_config():
    """重新加载配置"""
    global _manager
    with _manager_lock:
        if _manager is not None:
            _manager.reset()


# 为了兼容性，提供简化的日志函数
def log_info(message: str, **kwargs):
    """记录INFO级别日志"""
    logger = get_logger("app")
    logger.info(message, **kwargs)


def log_warn(message: str, **kwargs):
    """记录WARN级别日志"""
    logger = get_logger("app")
    logger.warning(message, **kwargs)


def log_error(message: str, **kwargs):
    """记录ERROR级别日志"""
    logger = get_logger("app")
    logger.error(message, **kwargs)